#pragma once

#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include "v2d.h"
#include "player.h"
#include "map.h"
#include "rectangle.h"
#include "wander.h"

typedef enum Buttons
{
	BT_UP = 1,
	BT_DOWN = 2,
	BT_LEFT = 4,
	BT_RIGHT = 8,
	BT_QUIT = 16
};

class Game
{
private:
	V2D<int> dim, iter;
	Player player;
	bool run;
	int m_input;
	Map m_map;
	int m_delayTime;
public:
	bool isRunning()
	{
		return run;
	}
	void init()
	{
		dim.set(20, 15), iter.set(0,0);
		player.setPosition(V2D<int>(4,5));
		player.m_state = new WanderState(&player);
		run = true;
		m_input = 0;
	}

	Game():player(this)
	{
		init();
	}

	Game(char * a_filename):player(this)
	{
		init();
		m_map.load(a_filename);
		dim.setX(m_map.width);
		dim.setY(m_map.height);
	}

	/** @return the small are of the game that has changed */
	Rect update(int a_ms)
	{
		// made an inverted rectangle... makes addPoint work better
		Rect areaOfChange(20,20,-20,-20);
		m_delayTime = a_ms;
		// note: this will FAIL if a V2D is not the first member...
		V2D<int> * playerPos = (V2D<int>*)&player;
		V2D<int> oldPosition = *playerPos;
		if(m_input != 0)
		{
			int i = m_input;
			m_input = i;
		}
		switch(m_input)
		{
		case BT_UP:		playerPos->addY(-1);	break;
		case BT_LEFT:	playerPos->addX(-1);	break;
		case BT_DOWN:	playerPos->addY( 1);	break;
		case BT_RIGHT:	playerPos->addX( 1);	break;
		case BT_QUIT:	run=0;	break;
		default:
			player.update(a_ms);
		}
		m_input = 0;
		// we should not have moved here...
		bool oob = playerPos->getX() < 0
		|| playerPos->getY() < 0 
		|| playerPos->getX() >= dim.getX() 
		|| playerPos->getY() >= dim.getY();
		bool inBadPlace = false;
		if(!oob)inBadPlace = m_map.map[playerPos->getY()][playerPos->getX()] != '.';
		if(oob || inBadPlace)
		{
			*playerPos = oldPosition;
		}
		if(!playerPos->is(oldPosition))
		{
			areaOfChange.addPoint(oldPosition);
			areaOfChange.addPoint(*playerPos);
		}
		return areaOfChange;
	}

	void draw(Rect * dirtyRectangle)
	{
		COORD pos = {0,0};
		m_map.draw(dirtyRectangle, 0,0, ' ');
		if(!dirtyRectangle
		|| dirtyRectangle->contains(player.getPosition()))
		{
			pos.X = player.getPosition().getX();
			pos.Y = player.getPosition().getY();
			SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
			putchar(player.m_face);
		}
	}

	// Get the input from the keyboard and convert it to our "Buttons"
	void input(int a_input)
	{
		m_input = 0;

		switch(a_input)
		{
		case 'w':
			m_input |= BT_UP;
			break;
		case 'a':
			m_input |= BT_LEFT;
			break;
		case 'd':
			m_input |= BT_RIGHT;
			break;
		case 's':
			m_input |= BT_DOWN;
			break;
		case 'q':
			m_input |= BT_QUIT;
			break;
		}
	}

	void release()
	{
		m_map.release();
	}

	~Game()
	{
		release();
	}
};

